Your first Intel assembly language programs. Consider the following trivial C program. cis lclient03:~/class/oct14>more mainandfunct.c #include unsigned int getthree(); main () { unsigned int i; i = getthree(); printf("i = %8.8x\n", i); return; } unsigned int getthree() { return 3U; } cis lclient03:~/class/oct14>./a.out i = 00000003 cis lclient03:~/class/oct14> Instead of compiling the main program and function as a unit, we can break them into two separate files and allow the C compiler to compile them separately. GCC will invoke the linker to combine the two machine language programs into a single executable called "a.out". cis lclient03:~/class/oct14>more main.c #include unsigned int getthree(); main () { unsigned int i; i = getthree(); printf("i = %8.8x\n", i); return; } cis lclient03:~/class/oct14>more funct.c unsigned int getthree() { return 3U; } cis lclient03:~/class/oct14>gcc main.c funct.c cis lclient03:~/class/oct14>./a.out i = 00000003 cis lclient03:~/class/oct14> We can also assembly the files main.c and funct.c into two separate assembly language programs called main.s and funct.s and then ask gcc to combile the two assembly language programs to produce a.out. (Recall that the S switch tells GCC to translates a C program into a ".s" assembly language program and then exit). cis lclient03:~/class/oct14>gcc S main.c cis lclient03:~/class/oct14>gcc S funct.c cis lclient03:~/class/oct14>ls funct.c funct.s mainandfunct.c main.c main.s cis lclient03:~/class/oct14>gcc main.s funct.s cis lclient03:~/class/oct14>ls a.out funct.c funct.s mainandfunct.c main.c main.s cis lclient03:~/class/oct14>./a.out i = 00000003 cis lclient03:~/class/oct14> GCC is just as happy to combine C code (e.g. main.c) and assembly code (e.g. funct.s). cis lclient03:~/class/oct14>gcc main.c funct.s cis lclient03:~/class/oct14>./a.out i = 00000003 cis lclient03:~/class/oct14> The assembly code main.s is 29 lines long, but we are only interested in funct.s, which is only 13 lines long, and most of those lines are "boiler plate". cis lclient03:~/class/oct14>more funct.s .file "funct.c" .text .globl getthree .type getthree, @function getthree: pushl %ebp movl %esp, %ebp movl $3, %eax popl %ebp ret .size getthree, . getthree .ident "GCC: (GNU) 4.4.5 20101112 (Red Hat 4.4.5 2)" .section .note.GNU stack,"",@progbits If we copy this file to getesp.s and modify a couple of lines, we end up with a function that will return the current value in the 32 bit %esp stack pointer. Only a single line of code was changed, namely "movl $s, %eax" into "movl %esp, %eax". The other five changes are the result of changing the name of the source file (funct.c to getesp.c) and the entry address (getthree to getesp). The C main program has been changed to call the new function. cis lclient03:~/class/oct14>more newmain.c #include unsigned int getesp(); /* changed funct to getesp */ main () { unsigned int esp; /* changed i to esp */ esp = getesp(); /* i to esp, funct to getesp */ printf("esp = %8.8x\n", esp); /* changed i to esp twice */ return; } cis lclient03:~/class/oct14>more getesp.s .file "funct.c" # changed funct.c to getesp.c .text .globl getesp # changed getthree to getesp .type getesp, @function # changed getthree to getesp getesp: # changed getthree to getesp pushl %ebp movl %esp, %ebp movl %esp, %eax # changed "$3" to "%esp" popl %ebp ret .size getesp, . getesp # changed getthree to getesp twice .ident "GCC: (GNU) 4.4.5 20101112 (Red Hat 4.4.5 2)" .section .note.GNU stack,"",@progbits cis lclient03:~/class/oct14>gcc newmain.c getesp.s cis lclient03:~/class/oct14>./a.out esp = bfb183b8 cis lclient03:~/class/oct14> Your Next Impossible Mission (not really that hard) Write and test the following assembly language functions. C assignment Write and test the following assembly language functions geteax(), getebx(), getecx(), getedx(), getesi(), getedi(), getesp(), and getebp(). You should use one main program that calls all eight functions. Does your code always print the same 8 numbers? How are you going to convince yourself (and us) that your code is correct when most coding errors will still produce a program that prints 8 hex digits. B assignment 1. Rewrite getesp() getting rid of as much of the boiler plate as possible. Prizes awarded for the program with the smallest number of lines. 2. Combine the 8 functions into one assembly language program with 8 entry points geteax(), getebx(), getecx(), getedx(), getesi(), getedi(), getesp(), and getebp(). Test your code. A assignment (very tricky if the caller is main()) Write a program "unsigned int callersret()" that displays the value of the callers return address (the address that the caller will return to when it executes an ret instruction).